/****************************************************
	文件：FogWithDepthTexture.cs
	作者：HuskyT
	邮箱：1005240602@qq.com
	日期：2020/8/17 20:23:43
	功能：基于深度纹理的全局雾效
*****************************************************/

using System;
using UnityEngine;

namespace RenderingPractice
{
    public class FogWithDepthTexture : PostEffectsBase
    {
        [Range(0.0f, 3.0f), Tooltip("雾浓度")]
        public float FogDensity = 1.0f;
        [Tooltip("雾颜色")]
        public Color FogColor = Color.white;
        [Tooltip("雾的最低高度")]
        public float BottomHeight = 0.0f;
        [Tooltip("雾的最高高度")]
        public float TopHeight = 1.0f;
        public Shader FogShader;
        private Material mFogMat;

        private Camera mCamera;
        public Camera Camera
        {
            get
            {
                if (mCamera == null)
                {
                    mCamera = GetComponent<Camera>();
                }
                return mCamera;
            }
        }
        private Transform mCameraTrans;
        public Transform CameraTrans
        {
            get
            {
                if (mCameraTrans == null)
                {
                    mCameraTrans = Camera.transform;
                }
                return mCameraTrans;
            }
        }

        public Material FogMat
        {
            get
            {
                mFogMat = CheckShaderAndCreateMaterial(FogShader, mFogMat);
                return mFogMat;
            }
        }

        private void OnEnable()
        {
            Camera.depthTextureMode |= DepthTextureMode.Depth;
        }

        private void OnRenderImage(RenderTexture source, RenderTexture destination)
        {
            if (FogMat != null)
            {
                Matrix4x4 frustumCorners = Matrix4x4.identity; //存储

                float fov = Camera.fieldOfView;
                float near = Camera.nearClipPlane;
                float far = Camera.farClipPlane;
                float aspect = Camera.aspect;

                float halfHeight = near * Mathf.Tan(fov * 0.5f * Mathf.Deg2Rad);
                Vector3 toRight = CameraTrans.right * halfHeight * aspect;
                Vector3 toTop = CameraTrans.up * halfHeight;

                Vector3 topLeft = CameraTrans.forward * near + toTop - toRight;
                float scale = topLeft.magnitude / near;
                topLeft.Normalize();
                topLeft *= scale;

                Vector3 topRight = CameraTrans.forward * near + toRight + toTop;
                topRight.Normalize();
                topRight *= scale;

                Vector3 bottomLeft = CameraTrans.forward * near - toTop - toRight;
                bottomLeft.Normalize();
                bottomLeft *= scale;

                Vector3 bottomRight = CameraTrans.forward * near + toRight - toTop;
                bottomRight.Normalize();
                bottomRight *= scale;

                frustumCorners.SetRow(0, bottomLeft);
                frustumCorners.SetRow(1, bottomRight);
                frustumCorners.SetRow(2, topRight);
                frustumCorners.SetRow(3, topLeft);

                FogMat.SetMatrix("_FrustumCorners", frustumCorners);
                FogMat.SetMatrix("_ViewProjInverseMatrix", (Camera.projectionMatrix * Camera.worldToCameraMatrix).inverse);

                FogMat.SetFloat("_FogDensity", FogDensity);
                FogMat.SetColor("_FogColor", FogColor);
                FogMat.SetFloat("_BottomHeight", BottomHeight);
                FogMat.SetFloat("_TopHeight", TopHeight);
                Graphics.Blit(source, destination, FogMat);
            }
            else
            {
                Graphics.Blit(source, destination);
            }
        }
    }
}